package com.wangyadong.hobby.javanetwork.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;

/**
 * <p>
 *
 * @author <714037465@qq.com>
 * @since 2019/7/1217:39
 **/
public class NioTest {

    public static int DEFAULT_PORT = 19;

    public static void main(String[] args) {
//        main1(args);
////        serverSocketChannal();
//        byte[] rotation = new byte[95 * 2];
//        for (byte i = ' '; i < '~'; i++) {
//            System.out.println("i--->" + i);
//            System.out.println(' ' + i);
//            rotation[i - ' '] = i;
//            rotation[i + 95 - ' '] = i;
//        }

        openSocket();
    }

    public static void main1(String[] args) {
        HashMap map=new HashMap();
        Object o = map.get(null);
        System.out.println(o);
    }


    public static void openSocket() {
        SocketAddress rama = new InetSocketAddress("localhost", 29);
        try {
            //创建一个链接，这个方法的唯一构造函数就是SocketAddress 用来指定连接的地址和端口，如果无法连接则会抛出异常
            SocketChannel client = SocketChannel.open(rama);
            // false 为不阻塞
            client.configureBlocking(false);
            //代替传统的输入输出流
            ByteBuffer buffer = ByteBuffer.allocate(74);
            client.read(buffer);
            //讲这个缓冲区传入read方法，read方法会
            WritableByteChannel output = Channels.newChannel(System.out);
            while (true) {
                int n = client.read(buffer);
                if (n > 0) {
                    buffer.flip();
                    output.write(buffer);
                    buffer.clear();
                } else if (n == -1) {
                    break;
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void serverSocketChannal() {
        try {
//            ServerSocketChannel serverSocket = ServerSocketChannel.open();
//            ServerSocket socket = serverSocket.socket();
//            socket.bind(new InetSocketAddress(19));
            //创建一个ServerSocketChannel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            ServerSocket serverSocket = serverSocketChannel.socket();
            // 绑定了端口和地址
            serverSocket.bind(new InetSocketAddress("wwww.adsdsd.com", 19));
            //接受连接 ，没有则返回NULL
            SocketChannel clientChanne = serverSocketChannel.accept();
            //设置客户端为非阻塞
            clientChanne.configureBlocking(false);
            //设置服务器端为非阻塞
            serverSocketChannel.configureBlocking(false);
            // 避免为每个连接创建一个线程
            Selector selector = Selector.open();
            //服务端
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            //客户端
            SelectionKey key = clientChanne.register(selector, SelectionKey.OP_WRITE);
            //345
            byte[] rotation = new byte[95 * 2];
            for (byte i = ' '; i < '~'; i++) {
                System.out.println("i--->" + i);
                rotation[i - ' '] = i;
                rotation[i + 95 - ' '] = i;
            }

            ByteBuffer buffer = ByteBuffer.allocate(74);
            buffer.put(rotation, 0, 72);
            buffer.put((byte) '\t');
            buffer.put((byte) '\n');

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void serverSocketChannal1() {
        byte[] rotation = new byte[95 * 2];
        for (byte i = ' '; i < '~'; i++) {
            System.out.println("i--->" + i);
            System.out.println(' ' + i);
            rotation[i - ' '] = i;
            rotation[i + 95 - ' '] = i;
        }

        ServerSocketChannel socketChannel = null;//服务端通道
        Selector selector = null;
        try {
            socketChannel = ServerSocketChannel.open();
            //java7 之后可以直接绑定
            socketChannel.bind(new InetSocketAddress(19));
            //服务端监听，如果此时没有入站数据，则会返回null
            SocketChannel clientChannel = socketChannel.accept();//客户端通道
            Optional<SocketChannel> channelOptional = Optional.ofNullable(clientChannel);
            if (channelOptional.isPresent()) {
                return;
            }
            //设置为非阻塞的
            socketChannel.configureBlocking(false);
            clientChannel.configureBlocking(false);
            //打开选择器
            selector = Selector.open();
            clientChannel.register(selector, SelectionKey.OP_WRITE);//只关注写入
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);//只关注是否可以开通一个新的连接
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        while (true) {
            try {
                selector.select();
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
            Set<SelectionKey> readKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        System.out.println("Accepted connection from " + client);
                        client.configureBlocking(false);
                        SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
                        ByteBuffer buffer = ByteBuffer.allocate(74);
                        //这些数字代表什么
                        buffer.put(rotation, 0, 72);
                        buffer.put((byte) '\t');
                        buffer.put((byte) '\n');
                        buffer.flip();
                        key2.attach(buffer);
                    } else if (key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        if (!buffer.hasRemaining()) {
                            buffer.rewind();
                            //得到上一次的手字符
                            int first = buffer.get();
                            buffer.rewind();
                            int position = first - ' ' + 1;
                            //寻找rotaion中的首字母位置
                            //将数据从rotation复制到缓冲区
                            buffer.put(rotation, position, 72);
                            //在缓冲区从末尾存储风分隔符
                            buffer.put((byte) '\t');
                            buffer.put((byte) '\n');
                            buffer.flip();
                        }
                        client.write(buffer);

                    }
                } catch (IOException e) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException e1) {

                    }
                }

            }
        }
    }

    /**
     * 缓冲区包含的信息
     *
     * @param args
     */
    public static void buffer(String[] args) {
        /***
         * 1.position位置
         * 读写操作
         *
         * 2.容量
         *
         * 3.限度limit  可读可写的位置
         * limit(int new)改变
         *
         * 4.标记mark
         *
         *
         */
    }


    public static void nioTest() {
        SocketAddress address = new InetSocketAddress("localhost", 13);
        try {
            //构建通道
            SocketChannel client = SocketChannel.open(address);
            //分配缓冲区
            ByteBuffer allocate = ByteBuffer.allocate(74);
            WritableByteChannel newChannel = Channels.newChannel(System.out);
            while (client.read(allocate) != -1) {
                // 通道读取缓冲
                allocate.flip();//告诉程序从缓冲中第一个字节开始读取,也是告诉程序准备写入
                newChannel.write(allocate);
                allocate.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

